package com.zrsx.searchmodel.service.serviceImpl;

import com.zrsx.searchmodel.common.entity.CreditInterpretation;
import com.zrsx.searchmodel.common.entity.User;
import com.zrsx.searchmodel.common.vo.DimensionVO;
import com.zrsx.searchmodel.common.vo.RankDisplayVO;
import com.zrsx.searchmodel.mapper.CreditDimensionMapper;
import com.zrsx.searchmodel.mapper.CreditScoreMapper;
import com.zrsx.searchmodel.common.vo.RankVO;
import com.zrsx.searchmodel.mapper.UserMapper;
import com.zrsx.searchmodel.service.CreditService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class CreditServiceImpl implements CreditService {
    @Autowired
    private CreditScoreMapper creditScoreMapper;
    @Autowired
    private CreditDimensionMapper creditDimensionMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;

    private static final String REDIS_KEY = "credit:rank";

    /**
     * 初始化Redis信用排名
     */
    @PostConstruct
    public void initCreditRank() {
        //优化的话，其实最好是异步在删除数据库的时候删除Redis，但是时间来不及了
        //这里是为了防止删除后重启模块，被删除用户的信息仍然存在 (但是全量加载会影响一定的性能TAT)
        redisTemplate.delete(REDIS_KEY); // 清空旧数据

        List<RankVO> credits = creditScoreMapper.getAllUserCredits();
        for (RankVO uc : credits) {
            redisTemplate.opsForZSet().add(REDIS_KEY, String.valueOf(uc.getUserId()), uc.getScore());
        }
    }

    /**
     * 接口实现部分 — 获取用户信用分
     * @param userId
     * @return
     */
    @Override
    public Integer getCredit(Integer userId) {
        Integer credit = creditScoreMapper.getCreditById(userId);
        return credit != null ? credit : 0;
    }

    /**
     * 接口实现部分 — 获取用户信用分排名
     * @param userId
     * @return
     */
    @Override
    public Long getRank(Integer userId) {
        //从Redis获取排名和分数
        Long rank = redisTemplate.opsForZSet().reverseRank(REDIS_KEY, String.valueOf(userId));
        return rank;
    }

    /**
     * 接口实现部分 — 获取单个维度分
     * @param id
     * @param dimension
     * @return
     */
    @Override
    public Integer getCreditDimension(Integer id, String dimension) {
        return creditDimensionMapper.getCreditDimension(id, dimension);
    }

    /**
     * 接口实现部分 — 获取所有维度分
     * @param id
     * @return
     */
    @Override
    public List<DimensionVO> getAllDimensions(Integer id) {
        return creditDimensionMapper.getAllDimensions(id);
    }

    /**
     * 接口实现部分 — 获取信用解读
     * @param userId
     * @return
     */
    @Override
    public CreditInterpretation getCreditInterpretation(Integer userId) {
        Integer creditScore = creditScoreMapper.getCreditById(userId);
        if (creditScore == null) {
            creditScore = 0;
        }
        // 1. 从Redis获取排名，注意 Redis 的排名是0基的
        Long rank = redisTemplate.opsForZSet().reverseRank(REDIS_KEY, String.valueOf(userId));
        if (rank == null) {
            rank = -1L; // 用户未上榜
        }
        // 2. 获取总用户数
        Long totalUsers = redisTemplate.opsForZSet().zCard(REDIS_KEY);
        if (totalUsers == null || totalUsers == 0) {
            totalUsers = 1L; // 避免除0错误
        }
        // 3. 计算百分位排名，排名从1开始
        double percentileRank;
        if (rank == -1L) {
            percentileRank = 0.0;
        } else {
            percentileRank = ((double)(totalUsers - rank)) / totalUsers * 100.0;
        }
        // 匹配信用评级标准区间
        String creditLevel = determineCreditLevel(creditScore);
        // 调用解释模板生成解读语句
        String interpretation = generateInterpretation(creditScore, creditLevel);
        // 生成个性化提示
        List<String> tips = generatePersonalizedTips(creditScore, creditLevel, percentileRank);
        // 创建并返回结果对象
        return CreditInterpretation.builder()
                .creditLevel(creditLevel)
                .creditScore(creditScore)
                .interpretation(interpretation)
                .behaviorTips(tips)
                .build();
    }

    /**
     * 获取信用分最高的前N名用户
     * @param topN
     * @return
     */
    @Override
    public List<RankDisplayVO> getTopCreditRank(int topN) {
        Set<ZSetOperations.TypedTuple<String>> topUsers =
                redisTemplate.opsForZSet().reverseRangeWithScores(REDIS_KEY, 0, topN - 1);

        if (topUsers == null) return Collections.emptyList();

        List<RankDisplayVO> result = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> tuple : topUsers) {
            Integer userId = Integer.valueOf(tuple.getValue());
            Double score = tuple.getScore();

            // 从用户表中查找昵称、头像
            User user = userMapper.selectById(userId);
            if (user != null) {
                result.add(new RankDisplayVO(userId, user.getNickName(), user.getProfilePicture(), score));
            }
        }

        return result;
    }


    //业务辅助方法

    // 判断信用等级
    public String determineCreditLevel(Integer newTotalScore){
        // 850+为信用极好 850-750为信用较好 750-600信用一般 600-450信用较差 450-信用极差 -1是未评级
        if(newTotalScore >= 850){
            return "信用极好";
        }else if(newTotalScore >= 750){
            return "信用较好";
        }else if(newTotalScore >= 600){
            return "信用一般";
        }else if(newTotalScore >= 450){
            return "信用较差";
        }else if(newTotalScore == 0) {
            return "未评级";
        } else{
            return "信用极差";
        }
    }

    // 生成信用解读语句
    private String generateInterpretation(Integer score, String level) {
        Map<String, String> templates = new HashMap<>();
        templates.put("信用极好", String.format("您的信用分(%d)高于平均水平，处于%s区间", score, level));
        templates.put("信用较好", String.format("您的信用分(%d)处于%s区间", score, level));
        templates.put("信用一般", String.format("您的信用分(%d)处于%s区间", score, level));
        templates.put("信用较差", String.format("您的信用分(%d)处于%s区间", score, level));
        templates.put("信用极差", String.format("您的信用分(%d)较低，请尽快改善信用行为", score));

        if ("未评级".equals(level)) {
            return "您的信用仍未认证评级。";
        }

        return templates.getOrDefault(level, "您的信用状况正常。");
    }


    //TODO 需要优化
    // 生成个性化行为提示
    private List<String> generatePersonalizedTips(Integer score, String level, double percentile) {
        List<String> tips = new ArrayList<>();

        // 基于信用等级的提示
        switch (level) {
            case "优秀":
                tips.add("您的信用评级为优秀，继续保持当前良好的信用习惯。");
                break;
            case "良好":
                tips.add("您的信用评级良好，距离优秀只有一步之遥。");
                break;
            case "中等":
                tips.add("您的信用评级中等，建议减少负债，提高还款能力。");
                break;
            case "较差":
                tips.add("您的信用评级较低，建议制定还款计划，逐步改善信用状况。");
                break;
        }

        // 基于百分位排名的提示
        if (percentile >= 90) {
            tips.add(String.format("您的信用分超过了 %.0f%% 的用户，表现优异！", percentile));
            tips.add("建议定期查看信用报告，维护良好记录。");
        } else if (percentile >= 75) {
            tips.add(String.format("您的信用分超过了 %.0f%% 的用户，继续保持！", percentile));
            tips.add("保持按时还款，有助于提升信用等级，建议关注信用行为，避免逾期。");
        } else if (percentile >= 50) {
            tips.add(String.format("您的信用分超过了 %.0f%% 的用户，还有提升空间。", percentile));
            tips.add("建议尽快偿还逾期欠款，避免影响信用评分。");
        } else {
            tips.add(String.format("您的信用分超过了 %.0f%% 的用户，建议优化信用行为。", percentile));
            tips.add("建议咨询客服，了解信用提升方法，同时参加亲社会活动进行提分。");
        }

        // 随机提示
        String[] randomTips = {
                "按时缴纳水电费等生活账单也有助于维护信用。",
                "合理使用信用卡，避免信用卡套现等不良行为。",
                "不要随意为他人提供担保，可能影响自身信用。",
                "定期查询信用报告，及时发现并纠正错误信息。"
        };

        // 随机选择1-2条提示，增加"个性化"感觉
        //TODO 还需要优化
        Random random = new Random();
        int count = random.nextInt(2) + 1;
        for (int i = 0; i < count; i++) {
            tips.add(randomTips[random.nextInt(randomTips.length)]);
        }

        return tips;
    }
}
